package com.ccx.demo.business.user.controller;

import com.alibaba.fastjson.JSONObject;
import com.ccx.demo.business.common.vo.UserFileInfo;
import com.ccx.demo.business.user.dto.TabUserInsertDTO;
import com.ccx.demo.business.user.dto.TabUserUpdateDTO;
import com.ccx.demo.business.user.entity.TabUser;
import com.ccx.demo.business.user.service.UserService;
import com.ccx.demo.business.user.vo.TabUserVO;
import com.ccx.demo.config.init.AppConfig;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSort;
import com.github.xiaoymin.knife4j.annotations.DynamicParameter;
import com.github.xiaoymin.knife4j.annotations.DynamicParameters;
import com.support.annotations.AppSwaggerGroup;
import com.support.annotations.VueSwaggerGroup;
import com.support.annotations.WechatSwaggerGroup;
import com.support.mvc.encrypt.AesApiId;
import com.support.mvc.entity.IUser;
import com.support.mvc.entity.base.Page;
import com.support.mvc.entity.base.Result;
import com.utils.util.Rsa;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 对外接口:用户
 *
 * @author 谢长春 on 2017/11/13.
 */
@Api(tags = "用户")
@ApiSort(4) // 控制接口排序
@RequestMapping("/user")
@Controller
@Slf4j
@RequiredArgsConstructor
public class UserController {

    private final UserService service;
    private final AppConfig appConfig;

    @AppSwaggerGroup
    @VueSwaggerGroup
    @WechatSwaggerGroup
    @ApiOperation(value = "1.获取当前登录用户", tags = {""})
    @ApiOperationSupport(order = 1, author = "谢长春")
    @GetMapping("/current")
    @ResponseBody
    public Result<TabUserVO> current(@ApiIgnore @AuthenticationPrincipal final TabUser user) {
        return new Result<TabUserVO>()
                .execute(result -> result.setSuccess(user.toTabUserVO()));
    }

    @VueSwaggerGroup
    @GetMapping("/page/{number}/{limit}")
    @PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'user_list_load')")
    @ApiOperation(value = "2.分页查询用户表", tags = {""})
    @ApiOperationSupport(
            order = 2,
            author = "谢长春",
            includeParameters = {"number", "limit", "orderBy", "deleted", "name", "createUserId", "updateUserId", "containsAll", "email", "nickname", "phone"}
    )
    @ResponseBody
    public Result<TabUserVO> pageVO(
            @ApiIgnore @AuthenticationPrincipal final IUser user,
            @ApiParam(required = true, value = "页码", example = "1") @PathVariable final int number,
            @ApiParam(required = true, value = "每页条数", example = "10") @PathVariable final int limit,
            final TabUserVO condition) {
        return new Result<TabUserVO>().execute(result -> result.setSuccess(service.pageVO(
                Optional.ofNullable(condition).orElseGet(TabUserVO::new),
                Page.builder().number(number).limit(limit).build()
        )));
    }

    @VueSwaggerGroup
    @GetMapping("/{encryptId}")
    @PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'user_list_load')")
    @ApiOperation(value = "3.按 encryptId 查询用户表", tags = {""})
    @ApiOperationSupport(order = 3, author = "谢长春")
    @ResponseBody
    public Result<TabUserVO> findById(
            @ApiIgnore @AuthenticationPrincipal final IUser user,
            @ApiParam(required = true, value = "加密id", example = "encryptId") @PathVariable final String encryptId) {
        return new Result<TabUserVO>().execute(result -> {
            final AesApiId.AesId decrypt = AesApiId.decrypt(encryptId);
            result.setSuccess(TabUserVO.ofTabUser(service.findById(decrypt.getLongId()).orElse(null)));
        });
    }

    @VueSwaggerGroup
    @PostMapping
    @PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'user_list_insert')")
    @ApiOperation(value = "4.新增用户表", tags = {""})
    @ApiImplicitParam(name = "body", dataType = "TabUserInsertDTO", dataTypeClass = TabUserInsertDTO.class, required = true)
    @ApiOperationSupport(
            order = 4,
            author = "谢长春",
            includeParameters = {
                    "body.username", "body.password", "body.nickname", "body.phone", "body.email", "body.avatar", "body.roleEncryptIds",
            }
    )
    @ResponseBody
    public Result<TabUserVO> insert(@ApiIgnore @AuthenticationPrincipal final IUser user,
                                    @RequestBody final TabUserInsertDTO body) {
        return new Result<TabUserVO>().execute(result -> {
            if (appConfig.getEncrypt().getPwd().isEnabled()) {
                // rsa 加密传输密码， 需要使用私钥解密
                body.setPassword(
                        Rsa.decryptByPrivateKey(
                                body.getPassword(),
                                appConfig.getEncrypt().getPwd().getPrivateKey()
                        )
                );
            }
            result.setSuccess(TabUserVO.ofTabUser(service.insert(body, user.getId())));
        });
    }

    @VueSwaggerGroup
    @PutMapping("/{encryptId}")
    @PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'user_list_update')")
    @ApiOperation(value = "5.修改用户表", tags = {""})
    @ApiImplicitParam(name = "body", dataType = "TabUserUpdateDTO", dataTypeClass = TabUserUpdateDTO.class, required = true)
    @ApiOperationSupport(
            order = 5,
            author = "谢长春",
            includeParameters = {
                    "body.nickname", "body.phone", "body.email", "body.avatar", "body.roleEncryptIds",
            })
    @ResponseBody
    public Result<Void> update(
            @ApiIgnore @AuthenticationPrincipal final IUser user,
            @ApiParam(required = true, value = "加密id", example = "encryptId") @PathVariable final String encryptId,
            @RequestBody final TabUserUpdateDTO body) {
        return new Result<Void>().call(() -> {
            final AesApiId.AesId decrypt = AesApiId.decrypt(encryptId);
            body.setUpdateTime(decrypt.getUpdateTime());
            service.update(decrypt.getLongId(), user.getId(), body);
        });
    }

    @VueSwaggerGroup
    @PatchMapping("/{encryptId}")
    @PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'user_list_delete')")
    @ApiOperation(value = "6.逻辑删除用户表", tags = {""})
    @ApiOperationSupport(order = 6, author = "谢长春")
    @ResponseBody
    public Result<Void> markDeleteById(
            @ApiIgnore @AuthenticationPrincipal final IUser user,
            @ApiParam(required = true, value = "加密id", example = "encryptId") @PathVariable final String encryptId) {
        return new Result<Void>().call(() -> {
            final AesApiId.AesId decrypt = AesApiId.decrypt(encryptId);
            service.markDeleteById(decrypt.getLongId(), decrypt.getUpdateTime(), user.getId());
        });
    }

    @VueSwaggerGroup
    @PatchMapping
    @PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'user_list_delete')")
    @ApiOperation(value = "7.批量逻辑删除用户表", tags = {""})
    @ApiOperationSupport(
            order = 7,
            author = "谢长春",
            params = @DynamicParameters(name = "EncryptIdArray", properties = {
                    @DynamicParameter(name = "EncryptIdArray", value = "加密id", example = "[encryptId,encryptId]", required = true, dataTypeClass = String[].class)
            })
    )
    @ResponseBody
    public Result<Void> markDelete(
            @ApiIgnore @AuthenticationPrincipal final IUser user,
            @RequestBody final Set<String> body
    ) {
        return new Result<Void>().call(() -> {
            if (body.isEmpty()) {
                return;
            }
            final List<AesApiId.AesId> decryptList = body.stream().map(AesApiId::decrypt).collect(Collectors.toList());
            service.markDelete(
                    decryptList.stream().map(AesApiId.AesId::getLongId).collect(Collectors.toSet())
                    , decryptList.stream().map(AesApiId.AesId::getUpdateTime).collect(Collectors.toSet())
                    , user.getId()
            );
        });
    }

    @AppSwaggerGroup
    @VueSwaggerGroup
    @WechatSwaggerGroup
    @PatchMapping("/nickname")
    @ApiOperation(value = "8.修改昵称", tags = {""})
    @ApiOperationSupport(
            order = 8,
            author = "谢长春",
            params = @DynamicParameters(name = "UpdateNickname", properties = {
                    @DynamicParameter(name = "nickname", value = "昵称", example = "Jack", required = true, dataTypeClass = String.class),
            })
    )
    @ResponseBody
    public Result<Void> updateNickname(
            @ApiIgnore @AuthenticationPrincipal final IUser user,
            @RequestBody final JSONObject body) {
        return new Result<Void>().call(() -> service.updateNickname(
                user.getId(),
                body.getString("nickname"),
                user.getId()
        ));
    }

    @VueSwaggerGroup
    @PatchMapping("/reset-password/{encryptId}")
    @PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'user_list_reset_password')")
    @ApiOperation(value = "9.重置密码，返回新密码", tags = {""})
    @ApiOperationSupport(order = 9, author = "谢长春")
    @ResponseBody
    public Result<String> resetPassword(
            @ApiIgnore @AuthenticationPrincipal final IUser user,
            @ApiParam(required = true, value = "加密id", example = "encryptId") @PathVariable final String encryptId) {
        return new Result<String>().execute(result -> {
            final AesApiId.AesId decrypt = AesApiId.decrypt(encryptId);
//            String newPassword = service.resetPassword(decrypt.getLongId(), user.getId());
//            if (appConfig.getEncrypt().getPwd().isEnabled()) {
//                // rsa 加密传输密码， 需要使用公钥解密
//                newPassword = Rsa.encryptByPrivateKey(newPassword, appConfig.getEncrypt().getPwd().getPrivateKey());
//            }
            result.setSuccess(service.resetPassword(decrypt.getLongId(), user.getId()));
        });
    }

    @AppSwaggerGroup
    @VueSwaggerGroup
    @WechatSwaggerGroup
    @PatchMapping("/change-password")
    @ApiOperation(value = "10.修改密码", tags = {""})
    @ApiOperationSupport(
            order = 10,
            author = "谢长春",
            params = @DynamicParameters(name = "ChangePassword", properties = {
                    @DynamicParameter(name = "passwordOld", value = "原密码", example = "111111", required = true, dataTypeClass = String.class),
                    @DynamicParameter(name = "passwordNew", value = "新密码", example = "111111", required = true, dataTypeClass = String.class),
            })
    )
    @ResponseBody
    public Result<Void> changePassword(
            @ApiIgnore @AuthenticationPrincipal final IUser user,
            @RequestBody(required = false) final JSONObject body
    ) {
        return new Result<Void>().call(() -> service.changePassword(
                user.getId(),
                body.getString("passwordOld"),
                body.getString("passwordNew")
        ));
    }

    @AppSwaggerGroup
    @VueSwaggerGroup
    @WechatSwaggerGroup
    @PatchMapping("/change-avatar")
    @ApiOperation(value = "11.修改头像", tags = {""})
    @ApiOperationSupport(order = 11, author = "谢长春")
    @ResponseBody
    public Result<Void> changeAvatar(
            @ApiIgnore @AuthenticationPrincipal final IUser user,
            @RequestBody(required = false) final UserFileInfo body
    ) {
        return new Result<Void>().call(() -> service.changeAvatar(user.getId(), body));
    }

    @VueSwaggerGroup
    @PatchMapping("/enable/{encryptId}")
    @PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'user_list_enable')")
    @ApiOperation(value = "12.启用", tags = {""})
    @ApiOperationSupport(order = 12, author = "谢长春")
    @ResponseBody
    public Result<Void> enable(
            @ApiIgnore @AuthenticationPrincipal final IUser user,
            @ApiParam(required = true, value = "加密id", example = "encryptId") @PathVariable final String encryptId) {
        return new Result<Void>().call(() -> {
            final AesApiId.AesId decrypt = AesApiId.decrypt(encryptId);
            service.updateDisabled(decrypt.getLongId(), false, user.getId());
        });
    }

    @VueSwaggerGroup
    @PatchMapping("/disable/{encryptId}")
    @PreAuthorize("hasAnyAuthority('ROLE_ADMIN', 'user_list_disable')")
    @ApiOperation(value = "13.禁用", tags = {""})
    @ApiOperationSupport(order = 13, author = "谢长春")
    @ResponseBody
    public Result<Void> disable(
            @ApiIgnore @AuthenticationPrincipal final IUser user,
            @ApiParam(required = true, value = "加密id", example = "encryptId") @PathVariable final String encryptId) {
        return new Result<Void>().call(() -> {
            final AesApiId.AesId decrypt = AesApiId.decrypt(encryptId);
            service.updateDisabled(decrypt.getLongId(), true, user.getId());
        });
    }

}
